/*
 * @Title Java8.java
 * @Description
 * @Copyright Copyright(c) 2018
 * @Company com.lizhen
 * @author lizhen
 * @version 0.0.1
 */
package com.lizhen.core.function.java8;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author lizhen
 */
public class Java8 {

    /**
     * @author lizhen
     */
    public Java8() {
    }

    /**
     * @author lizhen
     */
    public static void main(String[] args) {
        Lambda.main(null);
        StaticMethod.main(null);
        FunctionInterface.main(null);
        DefaultMethod.main(null);
        DataStream.main(null);
        JJS.main(null);
        Base64Demo.main(null);
    }

    static class Lambda {

        public static void main(String args[]) {
            Lambda lambda = new Lambda();
            MathOperation addition = (int a, int b) -> a + b;
            MathOperation subtraction = (a, b) -> a - b;
            MathOperation multiplication = (int a, int b) -> {
                return a * b;
            };
            MathOperation division = (int a, int b) -> a / b;

            System.out.println("10 + 5 = " + lambda.operate(10, 5, addition));
            System.out.println("10 - 5 = " + lambda.operate(10, 5, subtraction));
            System.out.println("10 x 5 = " + lambda.operate(10, 5, multiplication));
            System.out.println("10 / 5 = " + lambda.operate(10, 5, division));

            GreetingService greetService1 = message -> System.out.println("Hello " + message);
            GreetingService greetService2 = (message) -> System.out.println("Hello " + message);
            greetService1.sayMessage("Mahesh");
            greetService2.sayMessage("Suresh");
        }

        private int operate(int a, int b, MathOperation mathOperation) {
            return mathOperation.operation(a, b);
        }

        interface MathOperation {
            int operation(int a, int b);
        }

        interface GreetingService {
            void sayMessage(String message);
        }

    }

    static class StaticMethod {
        public static void main(String args[]) {
            List<String> names = new ArrayList<>();
            names.add("Mahesh");
            names.add("Suresh");
            names.add("Ramesh");
            names.add("Naresh");
            names.add("Kalpesh");

            names.forEach(System.out::println);
        }
    }

    static class FunctionInterface {

        public static void eval(List<Integer> list, Predicate<Integer> predicate) {
            for (Integer n : list) {
                if (predicate.test(n)) {
                    System.out.println(n + " ");
                }
            }
        }

        public static void main(String args[]) {
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

            System.out.println("Print all numbers:");

            eval(list, n -> true);

            System.out.println("Print even numbers:");

            eval(list, n -> n % 2 == 0);

            System.out.println("Print numbers greater than 3:");

            eval(list, n -> n > 3);
        }

    }

    static class DefaultMethod {

        public static void main(String args[]) {
            Vehicle vehicle = new DefaultMethod().new Car();
            vehicle.print();
        }

        interface Vehicle {
            static void blowHorn() {
                System.out.println("Blowing horn!!!");
            }

            default void print() {
                System.out.println("I am a vehicle!");
            }
        }

        interface FourWheeler {
            default void print() {
                System.out.println("I am a four wheeler!");
            }
        }

        class Car implements Vehicle, FourWheeler {
            public void print() {
                Vehicle.super.print();
                FourWheeler.super.print();
                Vehicle.blowHorn();

                System.out.println("I am a car!");
            }
        }
    }

    static class DataStream {

        private static int getCountEmptyStringUsingJava7(List<String> strings) {
            int count = 0;
            for (String string : strings) {
                if (string.isEmpty()) {
                    count++;
                }
            }
            return count;
        }

        private static int getCountLength3UsingJava7(List<String> strings) {
            int count = 0;
            for (String string : strings) {
                if (string.length() == 3) {
                    count++;
                }
            }
            return count;
        }

        private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) {
            List<String> filteredList = new ArrayList<String>();
            for (String string : strings) {
                if (!string.isEmpty()) {
                    filteredList.add(string);
                }
            }
            return filteredList;
        }

        private static String getMergedStringUsingJava7(List<String> strings, String seperator) {
            StringBuilder stringBuilder = new StringBuilder();
            for (String string : strings) {
                if (!string.isEmpty()) {
                    stringBuilder.append(string);
                    stringBuilder.append(seperator);
                }
            }
            String mergedString = stringBuilder.toString();
            return mergedString.substring(0, mergedString.length() - 2);
        }

        private static List<Integer> getSquares(List<Integer> numbers) {
            List<Integer> squaresList = new ArrayList<Integer>();
            for (Integer number : numbers) {
                Integer square = new Integer(number.intValue() * number.intValue());
                if (!squaresList.contains(square)) {
                    squaresList.add(square);
                }
            }
            return squaresList;
        }

        private static int getMax(List<Integer> numbers) {
            int max = numbers.get(0);
            for (int i = 1; i < numbers.size(); i++) {
                Integer number = numbers.get(i);
                if (number.intValue() > max) {
                    max = number.intValue();
                }
            }
            return max;
        }

        private static int getMin(List<Integer> numbers) {
            int min = numbers.get(0);
            for (int i = 1; i < numbers.size(); i++) {
                Integer number = numbers.get(i);
                if (number.intValue() < min) {
                    min = number.intValue();
                }
            }
            return min;
        }

        private static int getSum(List<Integer> numbers) {
            int sum = numbers.get(0);
            for (int i = 1; i < numbers.size(); i++) {
                sum += numbers.get(i).intValue();
            }
            return sum;
        }

        private static int getAverage(List<Integer> numbers) {
            return getSum(numbers) / numbers.size();
        }

        public static void main(String args[]) {
            List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
            long countEmpty = getCountEmptyStringUsingJava7(strings);
            long countLength3 = getCountLength3UsingJava7(strings);
            List<String> filtered = deleteEmptyStringsUsingJava7(strings);
            String mergedString = getMergedStringUsingJava7(strings, ", ");
            List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
            // get list of square of distinct numbers
            List<Integer> squaresList = getSquares(numbers);
            List<Integer> integers = Arrays.asList(1, 2, 13, 4, 15, 6, 17, 8, 19);

            System.out.println("Using Java 7: ");
            System.out.println("List: " + strings);
            System.out.println("Empty Strings: " + countEmpty);
            System.out.println("Strings of length 3: " + countLength3);
            System.out.println("Filtered List: " + filtered);
            System.out.println("Merged String: " + mergedString);
            System.out.println("Squares List: " + squaresList);
            System.out.println("List: " + integers);
            System.out.println("Highest number in List : " + getMax(integers));
            System.out.println("Lowest number in List : " + getMin(integers));
            System.out.println("Sum of all numbers : " + getSum(integers));
            System.out.println("Average of all numbers : " + getAverage(integers));
            System.out.println("Random Numbers: ");
            Random random = new Random();
            for (int i = 0; i < 10; i++) {
                System.out.println(random.nextInt());
            }

            long lambdaCountEmpty = strings.stream().filter(string -> string.isEmpty()).count();
            long lambdaCountLength3 = strings.stream().filter(string -> string.length() == 3).count();
            List<String> lambdaFiltered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
            String lambdaMergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
            List<Integer> lambdaSquaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
            IntSummaryStatistics lambdaStats = integers.stream().mapToInt((x) -> x).summaryStatistics();
            long lambdaCountParallel = strings.parallelStream().filter(string -> string.isEmpty()).count();

            System.out.println("Using Java 8: ");
            System.out.println("List: " + strings);
            System.out.println("Empty Strings: " + lambdaCountEmpty);
            System.out.println("Strings of length 3: " + lambdaCountLength3);
            System.out.println("Filtered List: " + lambdaFiltered);
            System.out.println("Merged String: " + lambdaMergedString);
            System.out.println("Squares List: " + lambdaSquaresList);
            System.out.println("List: " + integers);
            System.out.println("Highest number in List : " + lambdaStats.getMax());
            System.out.println("Lowest  number in List : " + lambdaStats.getMin());
            System.out.println("Sum of all numbers : " + lambdaStats.getSum());
            System.out.println("Average of all numbers : " + (int) lambdaStats.getAverage());
            System.out.println("Random Numbers: ");
            random.ints().limit(10).sorted().forEach(System.out::println);
            System.out.println("Empty Strings: " + lambdaCountParallel);
        }

    }

    static class JJS {
        public static void main(String args[]) {
            ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
            ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
            String name = "Mahesh";
            try {
                nashorn.eval("print('" + name + "')");
                Integer result = (Integer) nashorn.eval("10 + 2");

                System.out.println(result);
            } catch (ScriptException e) {
                System.out.println("Error executing script: " + e.getMessage());
            }
        }
    }

    static class Base64Demo {
        public static void main(String args[]) {
            try {
                String base64EncodedString = Base64.getEncoder().encodeToString("lizhen?java8".getBytes("utf-8"));
                byte[] base64DecodedBytes = Base64.getDecoder().decode(base64EncodedString);
                String base64UrlEncodedString = Base64.getUrlEncoder().encodeToString("lizhen?java8".getBytes("utf-8"));
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < 10; ++i) {
                    stringBuilder.append(UUID.randomUUID().toString());
                }
                byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
                String base64MimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);

                System.out.println("Base64 Encoded String (Basic) :" + base64EncodedString);
                System.out.println("Original String: " + new String(base64DecodedBytes, "utf-8"));
                System.out.println("Base64 Encoded String (URL) :" + base64UrlEncodedString);
                System.out.println("Base64 Encoded String (MIME) :" + base64MimeEncodedString);
            } catch (UnsupportedEncodingException e) {
                System.out.println("Error :" + e.getMessage());
            }
        }
    }

}